import { Eureka as RawEureka } from 'eureka-js-client';
import * as url from 'url';
import { v4 } from 'internal-ip';

export interface EurekaConfig {
  appId: string;
  port: number;
  serviceUrls: string[];
  registerWithEureka: boolean;
  ipAddr?: string;
}

export class Eureka {
  eurekaClient: RawEureka;
  instanceId: string;
  constructor(config: EurekaConfig) {
    const ip = config.ipAddr || v4.sync();
    if (!ip) {
      throw new Error('不能自动解析ip地址,请传入ipAddr');
    }

    const port = config.port || parseInt(process.env.PORT || '', 10);
    if (!port) {
      throw new Error('不能确定端口，请传入port或设置process.env.PORT');
    }

    this.instanceId = `${ip}:${port}`;
    const clientOrigin = url.format({ protocol: 'http', hostname: `${ip}:${port}`, pathname: '/' });
    const options = {
      instance: {
        app: config.appId,
        instanceId: this.instanceId,
        hostName: ip,
        ipAddr: ip,
        statusPageUrl: url.resolve(clientOrigin, '/info'),
        healthCheckUrl: url.resolve(clientOrigin, '/healthcheck'),
        homePageUrl: clientOrigin,
        port: {
          $: port,
          '@enabled': 'true',
        },
        vipAddress: config.appId.toUpperCase(),
        dataCenterInfo: {
          '@class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
          name: 'MyOwn',
        },
      },
      eureka: {
        serviceUrls: {
          default: config.serviceUrls,
        },
        registerWithEureka: config.registerWithEureka,
        waitForRegistry: config.registerWithEureka,  // 未公开配置
      },
    };
    this.eurekaClient = new RawEureka(options as any);
  }

  start() {
    return new Promise((resolve, reject) => {
      this.eurekaClient.start((err, ...rest) => {
        if (err) {
          reject(err);
          return;
        }
        resolve(rest);
      });
    });
  }

  stop() {
    return new Promise((resolve, reject) => {
      this.eurekaClient.stop((err, ...rest) => {
        // 404 视为成功
        if (err && !/404/.test(err.message)) {
          reject(err);
          return;
        }
        resolve(rest);
      });
    });
  }

  getInstances(appId: string) {
    return this.eurekaClient.getInstancesByAppId(appId);
  }
}
